package xfile

import (
	"os"
	"path/filepath"
	"strings"

	"gitee.com/xuesongtao/gotool/internal"
)

type ParseFile struct {
	waitParseDir string
	skipDirMap   map[string]bool // 多个通过逗号隔开
	Filenames    []*FileInfo
}

func NewParseFile() *ParseFile {
	obj := &ParseFile{
		Filenames: make([]*FileInfo, 0),
	}
	return obj
}

func (p *ParseFile) Null() bool {
	return p.Len() == 0
}

func (p *ParseFile) Reset() {
	p.Filenames = make([]*FileInfo, 0)
}

// Len 返回解析的总数
func (p *ParseFile) Len() int {
	return len(p.Filenames)
}

// GetProFiles 获取项目路径
func (p *ParseFile) GetProFiles() []*FileInfo {
	return p.Filenames
}

// hiddenDir 判断是否为隐藏文件
func (p *ParseFile) hiddenDir(dir string) bool {
	_, file := filepath.Split(dir)
	return strings.HasPrefix(file, ".")
}

func (p *ParseFile) getTopDir(relativePath string) string {
	if relativePath == "" {
		return relativePath
	}
	i := strings.Index(relativePath, string(filepath.Separator))
	if i < 0 {
		return relativePath
	}
	return relativePath[:i]
}

func (p *ParseFile) getRelativePath(path string) string {
	return strings.TrimPrefix(strings.TrimPrefix(path, p.waitParseDir), "/")
}

func (p *ParseFile) skip(path string) bool {
	if path == "" {
		return true
	}

	if p.hiddenDir(path) {
		internal.Infof("path %q is hiddenDir, it will skip", path)
		return true
	}

	if p.skipDirMap[p.getTopDir(p.getRelativePath(path))] {
		internal.Infof("path %q is in skip top dir, it will skip", path)
		return true
	}
	return false
}

// SetSkipTopDir 设置需要跳过的一级文件夹
// dirs 多个通过逗号隔开
func (p *ParseFile) SetSkipTopDir(dirs ...string) *ParseFile {
	if p.skipDirMap == nil {
		p.skipDirMap = make(map[string]bool)
	}
	for _, dir := range dirs {
		dir = strings.Trim(dir, "")
		if dir == "" {
			continue
		}
		p.skipDirMap[dir] = true
	}
	return p
}

// Check 验证
func (p *ParseFile) Check() bool {
	tmpMap := make(map[string]int, len(p.Filenames))
	for _, v := range p.Filenames {
		tmpMap[v.AbsolutePath]++
	}
	for _, v := range tmpMap {
		if v > 1 {
			return false
		}
	}
	return true
}

// ParseHasSuffixFiles 解析项目中包含某后缀的文件
func (p *ParseFile) ParseHasSuffixFiles(path string, fileSuffix string) *ParseFile {
	// internal.Infof("path: %s, projectName: %s, fileSuffix: %s", path, projectName, fileSuffix)
	if p.waitParseDir == "" {
		p.waitParseDir = path
	}

	if p.skip(path) {
		return p
	}

	files, err := os.ReadDir(path)
	if err != nil {
		internal.Error("os.ReadDir is failed, err: ", err)
		return p
	}

	// 遍历项目
	for _, file := range files {
		tmpFilename := file.Name() // 文件名

		// 如果是 dir 就递归使用
		filename := filepath.Join(path, tmpFilename)
		if file.IsDir() {
			p.ParseHasSuffixFiles(filename, fileSuffix)
			continue
		}
		if strings.HasSuffix(filename, fileSuffix) {
			fileObj := &FileInfo{
				AbsolutePath: filename,
				RelativePath: p.getRelativePath(path),
				Filename:     tmpFilename,
			}
			p.Filenames = append(p.Filenames, fileObj)
		}
	}
	return p
}
